package com.lj.job.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.lj.common.utils.CheckUtils;
import com.lj.job.entity.ScheduleJob;
import com.lj.job.enums.ScheduleJobStatus;
import com.lj.job.mapper.JobMapper;
import com.lj.job.param.JobPageParam;
import com.lj.job.param.JobSaveParam;
import com.lj.job.param.JobUpdateParam;
import com.lj.job.result.JobInfoResult;
import com.lj.job.result.JobPageResult;
import com.lj.job.service.JobService;
import com.lj.job.utils.ScheduleUtils;
import com.lj.mp.standard.StandardServiceImpl;
import com.lj.mp.utils.PageQueryUtils;
import org.quartz.CronTrigger;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 定时任务 服务实现类
 * </p>
 *
 * @author luojing
 * @since 2025-03-20 15:23:28
 */
@Service
public class JobServiceImpl extends StandardServiceImpl<JobMapper, ScheduleJob> implements JobService, ApplicationRunner {

    @Autowired
    private Scheduler scheduler;

    @Override
    public IPage<JobPageResult> page(JobPageParam param) {
        return this.page(PageQueryUtils.getPage(param), getQueryWrapper(param)).convert(JobPageResult::of);
    }

    private LambdaQueryWrapper<ScheduleJob> getQueryWrapper(JobPageParam param) {
        return lambdaQueryWrapper()
                .eq(ObjectUtil.isNotEmpty(param.getBeanName()), ScheduleJob::getBeanName, param.getBeanName())
                .eq(ObjectUtil.isNotEmpty(param.getStatus()), ScheduleJob::getStatus, param.getStatus())
                ;
    }

    @Override
    public JobInfoResult info(Long id) {
        return JobInfoResult.of(this.getById(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(JobSaveParam param) {
        ScheduleJob entity = param.toEntity();
        entity.setStatus(ScheduleJobStatus.NORMAL);
        this.save(entity);
        // 启动定时任务
        ScheduleUtils.createScheduleJob(scheduler, entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(JobUpdateParam param) {
        ScheduleJob scheduleJob = this.getById(param.getId());
        CheckUtils.ifNull(scheduleJob, "任务不存在，无法更新!");
        ScheduleJob entity = param.toEntity();
        // 更新接口无法修改执行状态，如果这里不设置状态，那么会出现，任务已经暂停，但是修改后任务继续在执行的问题
        entity.setStatus(scheduleJob.getStatus());
        this.updateById(entity);
        ScheduleUtils.updateScheduleJob(scheduler, entity);
    }

    @Override
    public void delete(List<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        List<Long> list = new ArrayList<>();
        for (Long id : ids) {
            try {
                ScheduleUtils.deleteScheduleJob(scheduler, id);
                list.add(id);
            } catch (Exception ignored) {
            }
        }
        this.removeByIds(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void run(List<Long> ids) {
        for (Long id : ids) {
            ScheduleUtils.run(scheduler, this.getById(id));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pause(List<Long> ids) {
        List<Long> list = new ArrayList<>();
        for (Long id : ids) {
            try {
                ScheduleUtils.pauseJob(scheduler, id);
                list.add(id);
            } catch (Exception ignored) {
            }
        }
        updateStatus(list, ScheduleJobStatus.PAUSE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resume(List<Long> ids) {
        List<Long> list = new ArrayList<>();
        for (Long id : ids) {
            try {
                ScheduleUtils.resumeJob(scheduler, id);
                list.add(id);
            } catch (Exception ignored) {
            }
        }
        updateStatus(list, ScheduleJobStatus.NORMAL);
    }

    private void updateStatus(List<Long> ids, ScheduleJobStatus status) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        update(lambdaUpdateWrapper()
                .set(ScheduleJob::getStatus, status)
                .in(ScheduleJob::getId, ids)
        );
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<ScheduleJob> scheduleJobList = this.list();
        for (ScheduleJob scheduleJob : scheduleJobList) {
            // 判断quartz的表中是否有对应任务的触发器(主要是为了解决第一次启动时加载已有的定时任务的问题)
            CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getId());
            if (cronTrigger == null) {
                // 这个任务第一次执行，那么创建，它会持久化到quartz的表中
                ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
            } else {
                // 任务执行过，进行更新
                ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);
            }
        }
    }
}
